package com.coder.oj.admin.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.coder.oj.admin.mapstruct.OauthMapstruct;
import com.coder.oj.admin.query.OauthQuery;
import com.coder.oj.admin.vo.OauthVo;
import com.coder.oj.common.core.JsonPage;
import com.coder.oj.common.entity.AdminRole;
import com.coder.oj.common.entity.Oauth;
import com.coder.oj.common.entity.RoleOauth;
import com.coder.oj.common.exception.DataException;
import com.coder.oj.common.mapper.*;
import com.coder.oj.common.vo.TreeVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Bosen 2022/11/25 11:26
 **/
@Service
public class OauthService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private OauthMapper oauthMapper;

    @Autowired
    private RoleOauthMapper roleOauthMapper;

    @Autowired
    private OauthMapstruct oauthMapstruct;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private RoleMapper roleMapper;

    /**
     * 分页查询
     * @author Bosen 2023/1/4 23:34
     */
    public JsonPage<OauthVo> getOauthPage(OauthQuery params) {
        LambdaQueryWrapper<Oauth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(params.getRest()), Oauth::getRest, params.getRest());
        queryWrapper.like(StringUtils.isNotBlank(params.getName()), Oauth::getName, params.getName());
        queryWrapper.like(StringUtils.isNotBlank(params.getMark()), Oauth::getMark, params.getMark());
        queryWrapper.like(StringUtils.isNotBlank(params.getCollect()), Oauth::getCollect, params.getCollect());
        IPage<Oauth> page = oauthMapper.selectPage(new Page<>(params.getPage(), params.getPageSize()), queryWrapper);
        List<OauthVo> collect = page.getRecords().stream().map(entity -> {
            OauthVo vo = oauthMapstruct.toVO(entity);
            vo.setCreateBy(adminMapper.getAdminName(entity.getCreateBy()));
            vo.setUpdateBy(adminMapper.getAdminName(entity.getUpdateBy()));
            return vo;
        }).collect(Collectors.toList());
        return new JsonPage<>(page.getCurrent(), page.getSize(), page.getTotal(), collect);
    }

    public List<OauthVo> getOauthList() {
        return oauthMapper.selectList(Wrappers.emptyWrapper()).stream().map(entity -> {
            OauthVo vo = oauthMapstruct.toVO(entity);
            vo.setCreateBy(adminMapper.getAdminName(entity.getCreateBy()));
            vo.setUpdateBy(adminMapper.getAdminName(entity.getUpdateBy()));
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 删除权限
     * @author Bosen 2022/12/27 13:44
     **/
    public void deleteOauth(Long id) {
        LambdaQueryWrapper<RoleOauth> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleOauth::getOauthId, id);
        if(roleOauthMapper.selectCount(queryWrapper) > NumberUtils.INTEGER_ZERO) {
            throw new DataException("该权限已被绑定");
        }
        oauthMapper.deleteById(id);
    }

    /**
     * 角色权限
     * @author Bosen 2022/12/27 13:46
     **/
    public List<OauthVo> getOauthsByRoleId(Long id) {
        List<RoleOauth> roleOauths = new LambdaQueryChainWrapper<>(roleOauthMapper)
                .eq(RoleOauth::getRoleId, id).list();
        List<Long> oauthIds = roleOauths.stream().map(item ->
                oauthMapper.selectById(item.getOauthId()).getId()
        ).collect(Collectors.toList());
        return oauthIds.stream().map(oauthId ->
                oauthMapstruct.toVO(oauthMapper.selectById(oauthId))
        ).collect(Collectors.toList());
    }

    /**
     * 角色权限id集合
     * @author Bosen 2022/12/27 13:48
     **/
    public List<String> getOauthIdsByRoleId(Long id) {
        List<RoleOauth> roleOauths = new LambdaQueryChainWrapper<>(roleOauthMapper)
                .eq(RoleOauth::getRoleId, id).list();
        return roleOauths.stream().map(
                item -> String.valueOf(item.getOauthId())
        ).collect(Collectors.toList());
    }
    
    /**
     * 管理员权限
     * @author Bosen 2023/1/1 23:45
     */
    public List<OauthVo> getOauthByAdminId(Long id) {
        List<AdminRole> adminRoles = new LambdaQueryChainWrapper<>(adminRoleMapper)
                .eq(AdminRole::getAdminId, id).list();
        List<Long> roleIds = adminRoles.stream().map(item ->
                roleMapper.selectById(item.getRoleId()).getId()
        ).collect(Collectors.toList());
        List<RoleOauth> roleOauths = new LambdaQueryChainWrapper<>(roleOauthMapper)
                .in(RoleOauth::getRoleId, roleIds).list();
        return roleOauths.stream().map(item ->
                oauthMapstruct.toVO(oauthMapper.selectById(item.getOauthId()))
        ).collect(Collectors.toList());
    }

    /**
     * 获取权限树
     * @author Bosen 2023/1/1 23:48
     */
    public List<TreeVo> getOauthTree() {
        List<String> collects = oauthMapper.getOauthCollect();
        List<TreeVo> vos = new ArrayList<>();
        long index = 0;
        for(String collect : collects) {
            List<Oauth> oauths = new LambdaQueryChainWrapper<>(oauthMapper)
                    .eq(Oauth::getCollect, collect).list();
            List<TreeVo> leafs = oauths.stream().map(oauth -> {
                TreeVo leaf = new TreeVo();
                leaf.setKey(oauth.getId());
                leaf.setLabel(oauth.getName());
                return leaf;
            }).collect(Collectors.toList());
            TreeVo root = new TreeVo();
            root.setKey(index++);
            root.setLabel(collect);
            root.setChildren(leafs);
            vos.add(root);
        }
        return vos;
    }
}
